I have written a new image_button component. It lets an administrator enter the location of an image within the site's theme. It also has a select control to determine whether the component should be a previous, next, or submit image button.

In order to support this, I have written a patch for webform.module. This patch does two things:

1) As part of building the form to present to a user, it looks for image buttons created by the image_button component. If it finds any, it removes the corresponding default button. So, for example, if there is a next image button, it will unset the default next button.

The patch also respects the logic of the webform module in that if there is a next image button, but there is no default next button, it will unset the image button on the assumption that there should not be a next button on the current page. I could see that administrators might find this annoying, and perhaps in future that will need to be changed. However, I think it makes sense to respect the logic of determining which pages should have which buttons.

2) The patch also modifies the form's submit function so that it will work correctly with Drupal's system for handling image_button elements. All it does is defer to $form_state['clicked_button']['#value'] if $form_state['values']['op'] does not provide a value.

One advantage of this overall approach is that image buttons can be placed anywhere within the layout of other components. Our clients often have webforms where they would prefer to have the buttons above some amount of content which is provided as part of the form. The image_button component makes it easy to accomplish this by dragging an image_button to wherever one wants it in the stack of components.

One downside of this approach is that it requires cloning if one wants to use the same button multiple times, but that seems unavoidable without moving up to a global level.

Comments

Sid_M’s picture

StatusFileSize
new3.49 KB

Patch for webform.module

Sid_M’s picture

StatusFileSize
new1.75 KB

New image_button component

Sid_M’s picture

Status: Active » Needs review
dkruglyak’s picture

Version: 6.x-2.5 » 6.x-2.x-dev
Category: feature » task
Status: Needs review » Reviewed & tested by the community

Working great for me. The only suggestion is to not constrain file paths to the theme directory.

Add an option of making them relative to site and/or files directory.

dkruglyak’s picture

StatusFileSize
new4.53 KB

A little fix is in order. The component does not use the right image src if webform is rendered in a block (using webformblock module). The reason is that _webform_render_image_button is called from within another theming call (theme_blocks) which supplies it wrong path to theme.

The solution is to retrieve the right path directly by using this code in _webform_render_image_button function:

  global $theme;
  init_theme();
  $themes = list_themes();
  $theme_obj = $themes[$theme];
  $path_to_theme = dirname($theme_obj->filename);

I attached the fully patched up image_button.inc file that has been tested and can be committed.

dkruglyak’s picture

StatusFileSize
new4.72 KB

OK, I got pretty frustrated with having to hard-code my paths into a theme, which could often be a problem. So I made a little update, similar to how WYSIWYG module handles CSS loading. Key difference is addition of this one line of code that makes theme path substitution optional:

  $image_url = strtr($src, array('%b' => base_path(), '%t' => $path_to_theme));

Note, I updated form field documentation and of course substituted $src for $image_url in the form.

Sid_M’s picture

Cool! Thanks for testing and improving.

djalloway’s picture

Sid_M, thanks for the patch and all your hard work, I do have one question though.
What are your thoughts on having this sort of functionality in the Advanced Settings of the Webform, instead of as a component?
Help me understand your decision process that lead you to use a component instead?
Thanks.

quicksketch’s picture

I also am a little baffled by the addition of the buttons as a component. What happens to the normal buttons on the form, or why not replace these buttons rather than add more buttons to the form? You can also accomplish the same thing already by theming the webform, which is what I'd suggest rather than putting display logic into the database.

dkruglyak’s picture

@quicksketch: To require theming would add unnecessary complexity - you have to write and maintain the code. There should definitely be a "quick-and-dirty" option to add image button and this is it. Besides making image button a component allows adding multiple buttons into a single form.

Normal buttons are replaced by the way and do not create a conflict. This has been tested.

Sid_M’s picture

Thanks for the questions djalloway and quickcatch. I hope the following adequately addresses them.

A minimal patch is needed to handle image buttons correctly

Drupal 6 has implemented a new way of dealing with image buttons in an attempt to deal with the fact that IE 6 does not return the value of a clicked image button. It makes use of $form_state['clicked_button']['#value']. As currently written, the webform module does not take this change into account. Thus simply converting buttons to image buttons will sometimes result in errors, especially in a case where there is more than one button on the form (for example, if there is both a back button and a submit button). So regardless of how we insert image buttons into webforms, we need to patch webform.module. See item 2 at the top of this page for a further description of my proposed fix for this issue.

What happens to the normal buttons?

They are unset when there is a corresponding image buttons. See the discussion in item 1 at the top of this page for more details.

Why a component not an advanced setting?

I often have cases where a client wants to put components both above and below the buttons. For example, they might have a contact us form where they want the user entry fields and submit button clustered together, all of them above a markup component providing information about how to contact the client by snail mail or telephone. Having the image button component makes it easy to achieve this.

It is solving this problem which I think makes the image button component solution more powerful than having image button functionality as part of the advanced settings for a web form. Advanced settings would let us use image buttons instead of regular buttons, but we would have no way of having some components above and other components below the buttons.

Why a component not a theme?

I may be wrong about this, but I don't think that any of the currently available themes would be adequate to allow having some components above the button(s), and others below the button(s).

Even if that could be achieved with a theme, that approach makes things more difficult than doing things through the UI. I believe it would be preferable if the client could do both of the following without having to edit a theme file (or hire me to edit the theme file for them):

  • Change the position of an image button relative to other components on the web form: i.e. move it up or down the stack of components.
  • Create a new webform which uses different button images than are used by any of the existing webforms.
quicksketch’s picture

Status: Reviewed & tested by the community » Needs work

Okay, well enough argued, a few more concerns if you can entertain my lingering doubts. Why make the patch specific to image buttons at all? It seems like several of your reasons would apply to normal buttons as well as image buttons. I'm not sure that "Submit" and "Next" should be separate actions. What happens when a user submits a form without completing later pages that have required fields? Merging them together seems logical.

Other than that this patch needs code style fixes:
- Use two space instead of tabs.
- Use underscores in variable names, $edit_fields instead of $editFields.
- Code comments should be complete sentences, with proper grammar and punctuation.

And some technical fixes:
- Looping through the entire form is unnecessary, these actions should be done during _webform_client_form_add_component(). Which will both eliminate the need to add an extra loop and handle buttons that are within fieldsets.
- The transliteration support is replaced with some broken characters in the #1 patch
- This needs to be rerolled for the 3.x version. I believe the $form_state['clicked_button'] is already in use in the 3.x version. The previous method was kept in place for consistency between the Drupal 5 and 6 version, but since the 3.x version is D6 only, we can now take full advantage of new APIs without worrying about the D5 version.

Sid_M’s picture

Version: 6.x-2.x-dev »
Status: Needs work » Needs review
StatusFileSize
new16.05 KB

I have updated the code, and attached a new patch which I very much hope satisfactorily addresses the various issues raised.

Before getting into the changes I made, I think it makes sense to be clearer about what I am and am not doing. I am not simply providing new buttons, but rather providing a means of overriding the default buttons that are already provided by webform. Although I am allowing overriding of the default buttons, I am not overriding the logic which decides what type(s) of button appear on each page. So, just like webform.module, I am supporting three types of button: previous, next, and submit. I am continuing to use webform's existing logic to determine what button(s) should be displayed on any given page of a form. This means that webform's logic, not the form administrator, has the final say as to what button types appear on each page of a form. For example, even if a form administrator puts a submit button on the middle page of a multipage form, that button will not be displayed because webform's logic says that a submit button should only go on the last page of a multipage form. Thus there is no need to worry about situations such as having a next button and a submit button on a middle page of a multipage form. (Although there may be some need to worry about form administrators being annoyed by this behavior. I leave it an open question whether it would be better if the module gave form administrators enough rope to hang themselves.)

At a functional level, this latest version has the following changes:

1) Both image buttons and regular buttons are supported. To keep both the code and the UI simple, I have done this by implementing a second component. Thus there are now two components: button and image button. These do pretty much the same thing except that one allows form administrators to override default buttons with image buttons, choosing the path to the image file, and the other allows them to override default buttons with regular buttons, choosing the text to display on the button. In either case, any button can go anywhere in the component stack, including having buttons of the same type at the top and bottom of the stack, if so desired.

2) I have slightly modified and extended the token system. Instead of %b and %t, I have implemented the following tokens: %base, %theme, and %files. I believe this covers the three main places where one would find an image file. I have opted for full name tokens instead of single letters because I think that makes things clearer to users, even if it means a little more typing.

At a code level, I have made the following changes:

1) I believe that the code now meets Drupal coding standards.

2) The latest patch is rolled against the 3.x version.

3) As suggested, I have rewritten it so it now does significant work within _webform_client_form_add_component(), and no longer loops through the entire form. In order to enable this, I have added a $button_states array which gets passed to _webform_client_form_add_component(). The button states are set by the same logic as determines which default button(s) to display on a page.

4) Although some of the module was taking advantage of the new $form_state['clicked_button'] protocol, this was not the case for the place I needed to change. I have, however, modified my change so it requires that protocol rather than making it optional. Thus I have replaced

if ($form_state['values']['op'] != $submit_op) {

with

if ($form_state['clicked_button']['#value'] != $submit_op) {

5) During my testing, I discovered that default previous buttons provided by the module were not working correctly in the 3.x version of the code. I looked into this, and discovered that the problem was that the updated module is now testing as follows

if (end($form_state['clicked_button']['#parents']) == 'prev' && $page_num > 1) {

However, the value for end($form_state['clicked_button']['#parents']) is the same as the name of the previous button's element in the form array. This was being set to "previous", and thus was never matching "prev". I have changed the name of the element in the form array to "prev". That seems to have done the trick.

Please note:

I see that the patch includes the following

- array(' ', '-', '€', 'ƒ', 'Š', 'Ž', 'š', 'ž', 'Ÿ', '¢', '¥', 'µ', 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'à', 'á', 'â', 'ã', 'ä', 'å', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', 'Œ', 'œ', 'Æ', 'Ð', 'Þ', 'ß', 'æ', 'ð', 'þ'),
+ array(' ', '-', '€', 'ƒ', 'Š', 'Ž', 'š', 'ž', 'Ÿ', '¢', '¥', 'µ', 'À', '�', 'Â', 'Ã', 'Ä', 'Å', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', '�', 'Î', '�', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', '�', 'à', 'á', 'â', 'ã', 'ä', 'å', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', 'Œ', 'œ', 'Æ', '�', 'Þ', 'ß', 'æ', 'ð', 'þ'),

I do not understand why that shows up as changed since I did not touch that line of code. I would recommend ignoring that change.

dkruglyak’s picture

Looks good, but my question is what is the status / plan / timeline for 3.x version?

What is changed? Is it working already? Alpha? Beta? Stable?

Sid_M’s picture

Status: Needs review » Needs work

Please don't review latest patch. I started refactoring, and found bugs. A newer version is coming soon.

Sid_M’s picture

Status: Needs work » Needs review
StatusFileSize
new17.49 KB

I have put this version through a fair amount of testing, and everything seems to work correctly.

The main difference between this and the previous patch in comment 13 is the that I modified where the code checks for whether the clicked button is a previous or next button by adding an additional case to handle overriding buttons. Thus the check for previous has-beens changed from

if (end($form_state['clicked_button']['#parents']) == 'prev' && $page_num > 1) {
  $page_num--;
}
elseif (end($form_state['clicked_button']['#parents']) == 'next' && $page_num < $page_count) {
  $page_num++;
}

to

if ($page_num > 1 && (end($form_state['clicked_button']['#parents']) == 'prev' || 
  $form_state['clicked_button']['#return_value'] == prev')) {
    $page_num--;
}
elseif ($page_num < $page_count && (end($form_state['clicked_button']['#parents']) == 'next' ||
  $form_state['clicked_button']['#return_value'] == 'next')) {
    $page_num++;
}

And basically the same changes been made for the check for next. Similarly, I modified the check for whether the clicked button is a submit button from

if ($form_state['values']['op'] != $submit_op) {

to

if ($form_state['clicked_button']['#value'] != $submit_op && $form_state['clicked_button']['#return_value'] != submit') {

Obviously, I changed the button and image button components so they provide the correct values for '$form_state['clicked_button']['#return_value'].

In addition, I refactored the code in _webform_client_form_add_component so it uses a loop instead of an if-elseif structure.

Sid_M’s picture

Since the above thread has gotten rather long and complicated, I thought it might be useful to write up a description of what this patch does and does not do for webform administrators. So here is some information about the new button and image button components implemented by the above patch.

The button and image button components are useful if you want to:

  • choose your own labels for next or previous buttons (you can also do this for submit buttons, but webform already supports that feature)
  • use image buttons instead of regular HTML buttons
  • allow creation of image buttons through the UI without needing to edit theme or code files
  • position your buttons within the stack of webform components rather than below them, for example, if you want the submit button above a markup component containing supplemental information
  • have more than one set of buttons, for example, have previous and next buttons both above and below a form's entry fields
  • have buttons appear differently on different pages of a multi-page form, for example, "back to 1", "back to 2", etc.

What the new button components do

Since the button and image button are components, you can add as many of them to a webform as you want to, positioning them wherever you want in the stack of components.

Each time you create a new instance of a button or image button component, you choose whether it should function as a previous, next or submit button. This new component will override the default button of the same kind. So, for example, if you add an image button, and set it to work as a submit button, the default submit button will not be added to the form.

Note that overriding one kind of default button does not affect the others. So you could override the previous button with a new component, but continue to use the default next and submit buttons. Also, since button placement is determined on a page by page basis, in a multi-page form, you could replace the default next button on one page, but not on another.

When creating an image button, you enter the path for the image to use. This supports the following tokens: %base, %theme, and %files. Thus once an image is in the filesystem, all you need to know is how to find it starting with either the base path, the path to theme, or the path inside the files folder.

What the new button components do not do

The button and image button components cannot create buttons which function in a way different from the default buttons provided by the webform module. That module provides three kinds of button:

  • Submit: appears only on the last page of a form. Its label reads "Submit".
  • Next: appears on every page except the last page of a form. Its label reads "Next >"
  • Previous: appears on every page except the first page of a form. Its label reads "< Previous".

Similarly, the button and image button components do not support adding buttons which do anything other than submit the form, go to the next page, or go to the previous page.

Since the new button components respect the above logic, if you add a button or image button component in a place where the webform module does not think a button of that kind should appear, the component will not appear. So, for example, if you add an image button to a single-page webform, and set it to go to the previous page, your previous image button will not appear in the form since single-page forms do not support previous buttons.

YK85’s picture

Version: » 6.x-3.x-dev

subscribing

csc4’s picture

suscribing

quicksketch’s picture

Status: Needs review » Closed (won't fix)

I don't plan on adding buttons as components. If desired, this should be made as a separate add-on module for Webform.